home *** CD-ROM | disk | FTP | other *** search
- /* See license.txt for terms of usage */
-
- FBL.ns(function() { with (FBL) {
-
- // ************************************************************************************************
- // Constants
-
- const saveTimeout = 400;
- const pageAmount = 10;
-
- // ************************************************************************************************
- // Globals
-
- var currentTarget = null;
- var currentGroup = null;
- var currentPanel = null;
- var currentEditor = null;
-
- var defaultEditor = null;
-
- var originalClassName = null;
-
- var originalValue = null;
- var defaultValue = null;
- var previousValue = null;
-
- var invalidEditor = false;
- var ignoreNextInput = false;
-
- // ************************************************************************************************
-
- Firebug.Editor = extend(Firebug.Module,
- {
- tabCharacter: " ",
-
- startEditing: function(target, value, editor)
- {
- this.stopEditing();
-
- if (hasClass(target, "insertBefore") || hasClass(target, "insertAfter"))
- return;
-
- var panel = Firebug.getElementPanel(target);
- if (!panel.editable)
- return;
-
- defaultValue = target.getAttribute("defaultValue");
- if (value == undefined)
- {
- value = target.textContent;
- if (value == defaultValue)
- value = "";
- }
-
- originalValue = previousValue = value;
-
- invalidEditor = false;
- currentTarget = target;
- currentPanel = panel;
- currentGroup = getAncestorByClass(target, "editGroup");
-
- currentPanel.editing = true;
-
- var panelEditor = currentPanel.getEditor(target, value);
- currentEditor = editor ? editor : panelEditor;
- if (!currentEditor)
- currentEditor = getDefaultEditor(currentPanel);
-
- var inlineParent = getInlineParent(target);
- var targetSize = getOffsetSize(inlineParent);
-
- setClass(panel.panelNode, "editing");
- setClass(target, "editing");
- if (currentGroup)
- setClass(currentGroup, "editing");
-
- currentEditor.show(target, currentPanel, value, targetSize);
- currentEditor.beginEditing(target, value);
-
- this.attachListeners(currentEditor, panel.context);
- },
-
- stopEditing: function(cancel)
- {
- if (!currentTarget)
- return;
-
- clearTimeout(this.saveTimeout);
- delete this.saveTimeout;
-
- this.detachListeners(currentEditor, currentPanel.context);
-
- removeClass(currentPanel.panelNode, "editing");
- removeClass(currentTarget, "editing");
- if (currentGroup)
- removeClass(currentGroup, "editing");
-
- var value = currentEditor.getValue();
- if (value == defaultValue)
- value = "";
-
- var removeGroup = currentEditor.endEditing(currentTarget, value, cancel);
-
- try
- {
- if (cancel)
- {
- if (value != originalValue)
- currentEditor.saveEdit(currentTarget, originalValue, previousValue);
-
- if (removeGroup && !originalValue && currentGroup)
- currentGroup.parentNode.removeChild(currentGroup);
- }
- else if (!value)
- {
- currentEditor.saveEdit(currentTarget, null, previousValue);
-
- if (removeGroup && currentGroup)
- currentGroup.parentNode.removeChild(currentGroup);
- }
- else
- this.save(value);
- }
- catch (exc)
- {
- ERROR(exc);
- }
-
- currentEditor.hide();
- currentPanel.editing = false;
-
- currentTarget = null;
- currentGroup = null;
- currentPanel = null;
- currentEditor = null;
- originalValue = null;
- invalidEditor = false;
-
- return value;
- },
-
- cancelEditing: function()
- {
- return this.stopEditing(true);
- },
-
- update: function(saveNow)
- {
- if (this.saveTimeout)
- clearTimeout(this.saveTimeout);
-
- invalidEditor = true;
-
- currentEditor.layout();
-
- if (saveNow)
- this.save();
- else
- {
- var context = currentPanel.context;
- this.saveTimeout = context.setTimeout(bindFixed(this.save, this), saveTimeout);
- }
- },
-
- save: function(value)
- {
- if (!invalidEditor)
- return;
-
- if (value == undefined)
- value = currentEditor.getValue();
-
- try
- {
- currentEditor.saveEdit(currentTarget, value, previousValue);
-
- previousValue = value;
- invalidEditor = false;
- }
- catch (exc)
- {
- ERROR(exc);
- }
- },
-
- setEditTarget: function(element)
- {
- if (!element)
- this.stopEditing();
- else if (hasClass(element, "insertBefore"))
- this.insertRow(element, "before");
- else if (hasClass(element, "insertAfter"))
- this.insertRow(element, "after");
- else
- this.startEditing(element, undefined, currentEditor);
- },
-
- tabNextEditor: function()
- {
- if (!currentTarget)
- return;
-
- var value = currentEditor.getValue();
- var nextEditable = currentTarget;
- do
- {
- nextEditable = !value && currentGroup
- ? getNextOutsider(nextEditable, currentGroup)
- : getNextByClass(nextEditable, "editable");
- }
- while (nextEditable && !nextEditable.offsetHeight);
-
- this.setEditTarget(nextEditable);
- },
-
- tabPreviousEditor: function()
- {
- if (!currentTarget)
- return;
-
- var value = currentEditor.getValue();
- var prevEditable = currentTarget;
- do
- {
- prevEditable = !value && currentGroup
- ? getPreviousOutsider(prevEditable, currentGroup)
- : getPreviousByClass(prevEditable, "editable");
- }
- while (prevEditable && !prevEditable.offsetHeight);
-
- this.setEditTarget(prevEditable);
- },
-
- insertRow: function(relative, insertWhere)
- {
- var value = this.stopEditing();
-
- if (!relative)
- relative = currentTarget;
-
- var group = getAncestorByClass(relative, "editGroup");
- if (!group)
- group = relative;
-
- currentPanel = Firebug.getElementPanel(group);
-
- currentEditor = currentPanel.getEditor(group, value);
- if (!currentEditor)
- currentEditor = getDefaultEditor(currentPanel);
-
- currentGroup = currentEditor.insertNewRow(group, insertWhere);
- if (!currentGroup)
- return;
-
- var editable = hasClass(currentGroup, "editable")
- ? currentGroup
- : getNextByClass(currentGroup, "editable");
-
- if (editable)
- this.setEditTarget(editable);
- },
-
- insertRowForObject: function(relative)
- {
- var container = getAncestorByClass(relative, "insertInto");
- if (container)
- {
- relative = getChildByClass(container, "insertBefore");
- if (relative)
- this.insertRow(relative, "before");
- }
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- attachListeners: function(editor, context)
- {
- var win = currentTarget.ownerDocument.defaultView;
- win.addEventListener("resize", this.onResize, true);
- win.addEventListener("blur", this.onBlur, true);
-
- var chrome = context.chrome;
-
- this.listeners = [
- chrome.keyCodeListen("ESCAPE", null, bind(this.cancelEditing, this)),
- ];
-
- if (editor.arrowCompletion)
- {
- this.listeners.push(
- chrome.keyCodeListen("UP", null, bindFixed(editor.completeValue, editor, -1)),
- chrome.keyCodeListen("DOWN", null, bindFixed(editor.completeValue, editor, 1)),
- chrome.keyCodeListen("PAGE_UP", null, bindFixed(editor.completeValue, editor, -pageAmount)),
- chrome.keyCodeListen("PAGE_DOWN", null, bindFixed(editor.completeValue, editor, pageAmount))
- );
- }
-
- if (currentEditor.tabNavigation)
- {
- this.listeners.push(
- chrome.keyCodeListen("RETURN", null, bind(this.tabNextEditor, this)),
- chrome.keyCodeListen("RETURN", isControl, bind(this.insertRow, this, null, "after")),
- chrome.keyCodeListen("TAB", null, bind(this.tabNextEditor, this)),
- chrome.keyCodeListen("TAB", isShift, bind(this.tabPreviousEditor, this))
- );
- }
- else if (currentEditor.multiLine)
- {
- this.listeners.push(
- chrome.keyCodeListen("TAB", null, insertTab)
- );
- }
- else
- {
- this.listeners.push(
- chrome.keyCodeListen("RETURN", null, bindFixed(this.stopEditing, this))
- );
-
- if (currentEditor.tabCompletion)
- {
- this.listeners.push(
- chrome.keyCodeListen("TAB", null, bind(editor.completeValue, editor, 1)),
- chrome.keyCodeListen("TAB", isShift, bind(editor.completeValue, editor, -1))
- );
- }
- }
- },
-
- detachListeners: function(editor, context)
- {
- if (!this.listeners)
- return;
-
- var win = currentTarget.ownerDocument.defaultView;
- win.removeEventListener("resize", this.onResize, true);
- win.removeEventListener("blur", this.onBlur, true);
-
- var chrome = context.chrome;
- if (chrome)
- {
- for (var i = 0; i < this.listeners.length; ++i)
- chrome.keyIgnore(this.listeners[i]);
- }
-
- delete this.listeners;
- },
-
- onResize: function(event)
- {
- currentEditor.layout(true);
- },
-
- onBlur: function(event)
- {
- if (currentEditor.enterOnBlur && isAncestor(event.target, currentEditor.box))
- this.stopEditing();
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- // extends Module
-
- initialize: function()
- {
- this.onResize = bindFixed(this.onResize, this);
- this.onBlur = bind(this.onBlur, this);
- },
-
- disable: function()
- {
- this.stopEditing();
- },
-
- showContext: function(browser, context)
- {
- this.stopEditing();
- },
-
- showPanel: function(browser, panel)
- {
- this.stopEditing();
- }
- });
-
- // ************************************************************************************************
- // BaseEditor
-
- Firebug.BaseEditor =
- {
- getValue: function()
- {
- },
-
- setValue: function(value)
- {
- },
-
- show: function(target, panel, value, textSize, targetSize)
- {
- },
-
- hide: function()
- {
- },
-
- layout: function(forceAll)
- {
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- beginEditing: function(target, value)
- {
- },
-
- saveEdit: function(target, value, previousValue)
- {
- },
-
- endEditing: function(target, value, cancel)
- {
- // Remove empty groups by default
- return true;
- },
-
- insertNewRow: function(target, insertWhere)
- {
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- startMeasuring: function(target)
- {
- if (!this.measureBox)
- {
- this.measureBox = target.ownerDocument.createElement("span");
- this.measureBox.className = "measureBox";
- }
-
- copyTextStyles(target, this.measureBox);
- target.ownerDocument.body.appendChild(this.measureBox);
- },
-
- measureText: function(value)
- {
- this.measureBox.innerHTML = value ? escapeHTML(value) : "m";
- return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1};
- },
-
- stopMeasuring: function()
- {
- this.measureBox.parentNode.removeChild(this.measureBox);
- }
- };
-
- // ************************************************************************************************
- // InlineEditor
-
- Firebug.InlineEditor = function(doc)
- {
- this.initializeInline(doc);
- };
-
- Firebug.InlineEditor.prototype = domplate(Firebug.BaseEditor,
- {
- tag:
- DIV({class: "inlineEditor"},
- DIV({class: "textEditorTop1"},
- DIV({class: "textEditorTop2"})
- ),
- DIV({class: "textEditorInner1"},
- DIV({class: "textEditorInner2"},
- INPUT({class: "textEditorInner", type: "text",
- oninput: "$onInput", onkeypress: "$onKeyPress", onoverflow: "$onOverflow"})
- )
- ),
- DIV({class: "textEditorBottom1"},
- DIV({class: "textEditorBottom2"})
- )
- ),
-
- expanderTag: IMG({class: "inlineExpander", src: "blank.gif"}),
-
- enterOnBlur: true,
- outerMargin: 8,
- shadowExpand: 7,
-
- initialize: function()
- {
- this.fixedWidth = false;
- this.completeAsYouType = true;
- this.tabNavigation = true;
- this.multiLine = false;
- this.tabCompletion = false;
- this.arrowCompletion = true;
- this.noWrap = true;
- this.numeric = false;
- },
-
- destroy: function()
- {
- this.destroyInput();
- },
-
- initializeInline: function(doc)
- {
- this.box = this.tag.replace({}, doc, this);
- this.input = this.box.childNodes[1].firstChild.firstChild; // XXXjjb childNode[1] required
- this.expander = this.expanderTag.replace({}, doc, this);
- this.initialize();
- },
-
- destroyInput: function()
- {
- // XXXjoe Need to remove input/keypress handlers to avoid leaks
- },
-
- getValue: function()
- {
- return this.input.value;
- },
-
- setValue: function(value)
- {
- // It's only a one-line editor, so new lines shouldn't be allowed
- return this.input.value = stripNewLines(value);
- },
-
- show: function(target, panel, value, targetSize)
- {
- this.target = target;
- this.panel = panel;
-
- this.targetSize = targetSize;
- this.targetOffset = getClientOffset(target);
-
- this.originalClassName = this.box.className;
-
- var classNames = target.className.split(" ");
- for (var i = 0; i < classNames.length; ++i)
- setClass(this.box, "editor-" + classNames[i]);
-
- // Make the editor match the target's font style
- copyTextStyles(target, this.box);
-
- this.setValue(value);
-
- if (this.fixedWidth)
- this.updateLayout(true);
- else
- {
- this.startMeasuring(target);
- this.textSize = this.measureText(value);
-
- // Correct the height of the box to make the funky CSS drop-shadow line up
- var parent = this.input.parentNode;
- if (hasClass(parent, "textEditorInner2"))
- {
- var yDiff = this.textSize.height - this.shadowExpand;
- parent.style.height = yDiff + "px";
- parent.parentNode.style.height = yDiff + "px";
- }
-
- this.updateLayout(true);
- }
-
- this.getAutoCompleter().reset();
-
- panel.panelNode.appendChild(this.box);
- this.input.select();
-
- // Insert the "expander" to cover the target element with white space
- if (!this.fixedWidth)
- {
- copyBoxStyles(target, this.expander);
-
- target.parentNode.replaceChild(this.expander, target);
- collapse(target, true);
- this.expander.parentNode.insertBefore(target, this.expander);
- }
-
- scrollIntoCenterView(this.box, null, true);
- },
-
- hide: function()
- {
- this.box.className = this.originalClassName;
-
- if (!this.fixedWidth)
- {
- this.stopMeasuring();
-
- collapse(this.target, false);
-
- if (this.expander.parentNode)
- this.expander.parentNode.removeChild(this.expander);
- }
-
- if (this.box.parentNode)
- {
- try { this.input.setSelectionRange(0, 0); } catch (exc) {}
- this.box.parentNode.removeChild(this.box);
- }
-
- delete this.target;
- delete this.panel;
- },
-
- layout: function(forceAll)
- {
- if (!this.fixedWidth)
- this.textSize = this.measureText(this.input.value);
-
- if (forceAll)
- this.targetOffset = getClientOffset(this.expander);
-
- this.updateLayout(false, forceAll);
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- beginEditing: function(target, value)
- {
- },
-
- saveEdit: function(target, value, previousValue)
- {
- },
-
- endEditing: function(target, value, cancel)
- {
- // Remove empty groups by default
- return true;
- },
-
- insertNewRow: function(target, insertWhere)
- {
- },
-
- advanceToNext: function(target, charCode)
- {
- return false;
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- getAutoCompleteRange: function(value, offset)
- {
- },
-
- getAutoCompleteList: function(preExpr, expr, postExpr)
- {
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- getAutoCompleter: function()
- {
- if (!this.autoCompleter)
- {
- this.autoCompleter = new Firebug.AutoCompleter(null,
- bind(this.getAutoCompleteRange, this), bind(this.getAutoCompleteList, this),
- true, false);
- }
-
- return this.autoCompleter;
- },
-
- completeValue: function(amt)
- {
- if (this.getAutoCompleter().complete(currentPanel.context, this.input, true, amt < 0))
- Firebug.Editor.update(true);
- else
- this.incrementValue(amt);
- },
-
- incrementValue: function(amt)
- {
- var value = this.input.value;
- var start = this.input.selectionStart, end = this.input.selectionEnd;
-
- var range = this.getAutoCompleteRange(value, start);
- if (!range || range.type != "int")
- range = {start: 0, end: value.length-1};
-
- var expr = value.substr(range.start, range.end-range.start+1);
- preExpr = value.substr(0, range.start);
- postExpr = value.substr(range.end+1);
-
- // See if the value is an integer, and if so increment it
- var intValue = parseInt(expr);
- if (!!intValue || intValue == 0)
- {
- var m = /\d+/.exec(expr);
- var digitPost = expr.substr(m.index+m[0].length);
-
- var completion = intValue-amt;
- this.input.value = preExpr + completion + digitPost + postExpr;
- this.input.setSelectionRange(start, end);
-
- Firebug.Editor.update(true);
-
- return true;
- }
- else
- return false;
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- onKeyPress: function(event)
- {
- if (event.keyCode == 27 && !this.completeAsYouType)
- {
- var reverted = this.getAutoCompleter().revert(this.input);
- if (reverted)
- cancelEvent(event);
- }
- else if (event.charCode && this.advanceToNext(this.target, event.charCode))
- {
- Firebug.Editor.tabNextEditor();
- cancelEvent(event);
- }
- else
- {
- if (this.numeric && event.charCode && (event.charCode < 48 || event.charCode > 57)
- && event.charCode != 45 && event.charCode != 46)
- FBL.cancelEvent(event);
- else
- {
- // If the user backspaces, don't autocomplete after the upcoming input event
- this.ignoreNextInput = event.keyCode == 8;
- }
- }
- },
-
- onOverflow: function()
- {
- this.updateLayout(false, false, 3);
- },
-
- onInput: function()
- {
- if (this.ignoreNextInput)
- {
- this.ignoreNextInput = false;
- this.getAutoCompleter().reset();
- }
- else if (this.completeAsYouType)
- this.getAutoCompleter().complete(currentPanel.context, this.input, false);
- else
- this.getAutoCompleter().reset();
-
- Firebug.Editor.update();
- },
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- updateLayout: function(initial, forceAll, extraWidth)
- {
- if (this.fixedWidth)
- {
- this.box.style.left = (this.targetOffset.x) + "px";
- this.box.style.top = (this.targetOffset.y) + "px";
-
- var w = this.target.offsetWidth;
- var h = this.target.offsetHeight;
- this.input.style.width = w + "px";
- this.input.style.height = (h-3) + "px";
- }
- else
- {
- if (initial || forceAll)
- {
- this.box.style.left = this.targetOffset.x + "px";
- this.box.style.top = this.targetOffset.y + "px";
- }
-
- var approxTextWidth = this.textSize.width;
- var maxWidth = (currentPanel.panelNode.scrollWidth - this.targetOffset.x)
- - this.outerMargin;
-
- var wrapped = initial
- ? this.noWrap && this.targetSize.height > this.textSize.height+3
- : this.noWrap && approxTextWidth > maxWidth;
-
- if (wrapped)
- {
- var style = this.target.ownerDocument.defaultView.getComputedStyle(this.target, "");
- targetMargin = parseInt(style.marginLeft) + parseInt(style.marginRight);
-
- // Make the width fit the remaining x-space from the offset to the far right
- approxTextWidth = maxWidth - targetMargin;
-
- this.input.style.width = "100%";
- this.box.style.width = approxTextWidth + "px";
- }
- else
- {
- // Make the input one character wider than the text value so that
- // typing does not ever cause the textbox to scroll
- var charWidth = this.textSize.width / Math.max(this.input.value.length, 1);
-
- // Sometimes we need to make the editor a little wider, specifically when
- // an overflow happens, otherwise it will scroll off some text on the left
- if (extraWidth)
- charWidth *= extraWidth;
-
- var inputWidth = approxTextWidth + charWidth;
-
- if (initial)
- this.box.style.width = "auto";
- else
- {
- var xDiff = this.box.scrollWidth - this.input.offsetWidth;
- this.box.style.width = (inputWidth + xDiff) + "px";
- }
-
- this.input.style.width = inputWidth + "px";
- }
-
- this.expander.style.width = approxTextWidth + "px";
- this.expander.style.height = (this.textSize.height-3) + "px";
- }
-
- if (forceAll)
- scrollIntoCenterView(this.box, null, true);
- }
- });
-
- // ************************************************************************************************
- // Autocompletion
-
- Firebug.AutoCompleter = function(getExprOffset, getRange, evaluator, selectMode, caseSensitive)
- {
- var candidates = null;
- var originalValue = null;
- var originalOffset = -1;
- var lastExpr = null;
- var lastOffset = -1;
- var exprOffset = 0;
- var lastIndex = 0;
- var preParsed = null;
- var preExpr = null;
- var postExpr = null;
-
- this.revert = function(textBox)
- {
- if (originalOffset != -1)
- {
- textBox.value = originalValue;
- textBox.setSelectionRange(originalOffset, originalOffset);
-
- this.reset();
- return true;
- }
- else
- {
- this.reset();
- return false;
- }
- };
-
- this.reset = function()
- {
- candidates = null;
- originalValue = null;
- originalOffset = -1;
- lastExpr = null;
- lastOffset = 0;
- exprOffset = 0;
- };
-
- this.complete = function(context, textBox, cycle, reverse)
- {
- var value = lastValue = textBox.value;
- var offset = textBox.selectionStart;
- if (!selectMode && originalOffset != -1)
- offset = originalOffset;
-
- if (!candidates || !cycle || offset != lastOffset)
- {
- originalOffset = offset;
- originalValue = value;
-
- // Find the part of the string that will be parsed
- var parseStart = getExprOffset ? getExprOffset(value, offset, context) : 0;
- preParsed = value.substr(0, parseStart);
- var parsed = value.substr(parseStart);
-
- // Find the part of the string that is being completed
- var range = getRange ? getRange(parsed, offset-parseStart, context) : null;
- if (!range)
- range = {start: 0, end: parsed.length-1 };
-
- var expr = parsed.substr(range.start, range.end-range.start+1);
- preExpr = parsed.substr(0, range.start);
- postExpr = parsed.substr(range.end+1);
- exprOffset = parseStart + range.start;
-
- if (!cycle)
- {
- if (!expr)
- return;
- else if (lastExpr && lastExpr.indexOf(expr) != 0)
- {
- candidates = null;
- }
- else if (lastExpr && lastExpr.length >= expr.length)
- {
- candidates = null;
- lastExpr = expr;
- return;
- }
- }
-
- lastExpr = expr;
- lastOffset = offset;
-
- var searchExpr;
-
- // Check if the cursor is at the very right edge of the expression, or
- // somewhere in the middle of it
- if (expr && offset != parseStart+range.end+1)
- {
- if (cycle)
- {
- // We are in the middle of the expression, but we can
- // complete by cycling to the next item in the values
- // list after the expression
- offset = range.start;
- searchExpr = expr;
- expr = "";
- }
- else
- {
- // We can't complete unless we are at the ridge edge
- return;
- }
- }
-
- var values = evaluator(preExpr, expr, postExpr, context);
- if (!values)
- return;
-
- if (expr)
- {
- // Filter the list of values to those which begin with expr. We
- // will then go on to complete the first value in the resulting list
- candidates = [];
-
- if (caseSensitive)
- {
- for (var i = 0; i < values.length; ++i)
- {
- var name = values[i];
- if (name.indexOf && name.indexOf(expr) == 0)
- candidates.push(name);
- }
- }
- else
- {
- var lowerExpr = caseSensitive ? expr : expr.toLowerCase();
- for (var i = 0; i < values.length; ++i)
- {
- var name = values[i];
- if (name.indexOf && name.toLowerCase().indexOf(lowerExpr) == 0)
- candidates.push(name);
- }
- }
-
- lastIndex = reverse ? candidates.length-1 : 0;
- }
- else if (searchExpr)
- {
- var searchIndex = -1;
-
- // Find the first instance of searchExpr in the values list. We
- // will then complete the string that is found
- if (caseSensitive)
- {
- searchIndex = values.indexOf(expr);
- }
- else
- {
- var lowerExpr = searchExpr.toLowerCase();
- for (var i = 0; i < values.length; ++i)
- {
- var name = values[i];
- if (name && name.toLowerCase().indexOf(lowerExpr) == 0)
- {
- searchIndex = i;
- break;
- }
- }
- }
-
- // Nothing found, so there's nothing to complete to
- if (searchIndex == -1)
- return this.reset();
-
- expr = searchExpr;
- candidates = cloneArray(values);
- lastIndex = searchIndex;
- }
- else
- {
- expr = "";
- candidates = [];
- for (var i = 0; i < values.length; ++i)
- {
- if (values[i].substr)
- candidates.push(values[i]);
- }
- lastIndex = -1;
- }
- }
-
- if (cycle)
- {
- expr = lastExpr;
- lastIndex += reverse ? -1 : 1;
- }
-
- if (!candidates.length)
- return;
-
- if (lastIndex >= candidates.length)
- lastIndex = 0;
- else if (lastIndex < 0)
- lastIndex = candidates.length-1;
-
- var completion = candidates[lastIndex];
- var preCompletion = expr.substr(0, offset-exprOffset);
- var postCompletion = completion.substr(offset-exprOffset);
-
- textBox.value = preParsed + preExpr + preCompletion + postCompletion + postExpr;
- var offsetEnd = preParsed.length + preExpr.length + completion.length;
- if (selectMode)
- textBox.setSelectionRange(offset, offsetEnd);
- else
- textBox.setSelectionRange(offsetEnd, offsetEnd);
-
- return true;
- };
- };
-
- // ************************************************************************************************
- // Local Helpers
-
- function getDefaultEditor(panel)
- {
- if (!defaultEditor)
- {
- var doc = panel.document;
- defaultEditor = new Firebug.InlineEditor(doc);
- }
-
- return defaultEditor;
- }
-
- function getOutsider(element, group, stepper)
- {
- var next = stepper(element);
- if (isAncestor(next, group))
- {
- do
- {
- next = stepper(next);
- }
- while (isAncestor(next, group) || hasClass(next, "insertBefore")
- || hasClass(next, "insertAfter"));
- }
-
- return next;
- }
-
- function getNextOutsider(element, group)
- {
- return getOutsider(element, group, bind(getNextByClass, FBL, "editable"));
- }
-
- function getPreviousOutsider(element, group)
- {
- return getOutsider(element, group, bind(getPreviousByClass, FBL, "editable"));
- }
-
- function getInlineParent(element)
- {
- var lastInline = element;
- for (; element; element = element.parentNode)
- {
- var s = element.ownerDocument.defaultView.getComputedStyle(element, "");
- if (s.display != "inline")
- return lastInline;
- else
- lastInline = element;
- }
- return null;
- }
-
- function insertTab()
- {
- insertTextIntoElement(currentEditor.input, Firebug.Editor.tabCharacter);
- }
-
- // ************************************************************************************************
-
- Firebug.registerModule(Firebug.Editor);
-
- // ************************************************************************************************
-
- }});
-